import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 
 * @author  
 * @date    2011-6-13
 * @file    .ScaUpdate.java
 */
public class ScaUpdate {

	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		if (args.length == 0){
			return;
		}
		// 1. 检索所有 sca 文件
		String base_dir = args[0];
		List<String> list = getAllFiles(base_dir, ".composite");
		
		// 2. 读取需要忽略的文件
		Set<String> ignore_list = new HashSet<String>();
		File ignore_file = new File("ignore_list.txt");
		if (!ignore_file.exists()){
			ignore_file.createNewFile();
		}
		BufferedReader buf = new BufferedReader(
				new InputStreamReader(new FileInputStream(ignore_file), "utf-8"));
		String line = null;
		while ((line = buf.readLine()) != null){
			line = line.trim();
			if (line.length() < 1){
				continue;
			}
			ignore_list.add(line);
		}
		buf.close();
		
		// 3. 依次更新 sca 文件
		for(String str : list){
			if (ignore_list.contains(str)){
				continue;
			}
			System.out.println("update.. " + str);
			try {
			    updateScaFile(str);
			    ignore_list.add(str);
			} catch (Exception e){
			    System.out.println("update failed.");	
			}			
		}
		
		// 4. 更新 ignore_list.txt
		PrintWriter pw = new PrintWriter(ignore_file);
		for (String str : ignore_list){
			pw.println(str);
		}
		pw.flush();
		pw.close();
	}
    /**
     * 返回目录 dir 及所有子目录中以 suffix 结尾的 文件
     * @param dir :String
     * @param suffix :String
     * @return List<String> fileAbsolutePath
     */
    public static List<String> getAllFiles(String dir,String suffix){
        List<String> list = new ArrayList<String>();
        File file = new File(dir);
        String filename = file.getName().toLowerCase(); // 文件名转小写
        if(file.isFile() && (filename.endsWith(suffix))){
            list.add(file.getAbsolutePath());           // 保存符合条件的文件路径
        } else if(file.isDirectory()){
            File[] fs = file.listFiles();
            for(File f : fs){                           // 遍历当前目录
                getAllFiles(f,suffix,list);             // 递归遍历子目录
            }
        }
        return list;
    } 
    /**
     * 取出目录 dir 及所有子目录中以 suffix 结尾的 文件
     * @param file :File
     * @param suffix :String
     * @param list :List<String>
     */
    private static void getAllFiles(File file,String suffix,List<String> list){
        String filename = file.getName().toLowerCase(); // 文件名转小写
        if(file.isFile() && (filename.endsWith(suffix))){
            list.add(file.getAbsolutePath());           // 保存符合条件的文件路径
        } else if(file.isDirectory()){
            File[] fs = file.listFiles();
            for(File f : fs){                           // 遍历当前目录
                getAllFiles(f,suffix,list);             // 递归遍历子目录
            }
        }
    }// end
    
    @SuppressWarnings("unchecked")
	public static void updateScaFile(String filePath) throws Exception{
    	// 1. 解析 sca
		SAXReader reader = new SAXReader();
		Document doc = reader.read(new File(filePath));
		Element root = doc.getRootElement();
		
		Composite composite = new Composite();
		composite.name = root.attributeValue("name");
		composite.desc = root.elementText("description");
		
		List<Element> comp_list = root.elements("component");
		for(Element el : comp_list){
			Component comp = new Component();
			comp.name = el.attributeValue("name");
			
			Element serv = el.element("service");
			comp.service = new Service();
			comp.service.name = serv.attributeValue("name");
			comp.service.interf = serv.element("interface.java").attributeValue("interface");
			
			comp.impl = el.element("implementation.java").attributeValue("impl");
			
			Element ref = el.element("reference");
			if (ref != null){
				comp.ref = new Ref();
				comp.ref.name = ref.attributeValue("name");
				comp.ref.target = ref.attributeValue("target");	
			}
			
			List<Element> props = el.elements("property");
			for (Element prop : props){
				Prop p = new Prop();
				p.name = prop.attributeValue("name");
				p.value = prop.attributeValue("value");
				comp.props.add(p);
			}
			
			composite.comps.add(comp);
		}
		
		// 2. 更新 sca
		composite.update();
		
		// 3. 输出
		PrintWriter pw = new PrintWriter(filePath);
		pw.print(composite.toString());
		pw.flush();
		pw.close();
    }
}
class Composite{
	public String name;
	public String desc;
	public List<Component> comps = new ArrayList<Component>();
	
	public void update(){
		// 1. 查找 SupperApproveSubmit 所在组件
		String oldCls = "org.loushang.gdyj.datachange.SupperApproveSubmit";
		
		int index = -1;
		for(int i=comps.size()-1; i>=0; i--){
			Component comp = comps.get(i);
			if (comp.impl.equals(oldCls)){
				index = i;
				break;
			}
		}
		if (index == -1){
			return;
		}
		Component prev = comps.get(index -1);
		Component curr = comps.get(index);
		Component next = comps.get(index + 1);
		
		next.ref = new Ref();
		next.ref.name = "nextComponent";
		
		String tmp = prev.ref.target;
		
		// 前一个..后一个
		prev.ref.target = curr.ref.target;
		// 后一个..当前
		next.ref.target = tmp;
		// 当前的下一个置为 null
		curr.ref = null;
		curr.impl = "org.loushang.gdyj.datachange.Submit2Ecgap";
		curr.props.remove(new Prop("jndiName"));
		
		comps.set(index, next);
		comps.set(index + 1, curr);
	}
	
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		sb.append("\r\n");
		sb.append("<composite name=\"" + name + "\" xmlns=\"http://www.loushang.com/sca/1.0\">");
		sb.append("\r\n");
		sb.append("    <description>" + desc + "</description>");
		sb.append("\r\n");
		sb.append("\r\n");
		for (Component comp : comps){
			sb.append(comp);
			sb.append("\r\n");
			sb.append("\r\n");
		}
		sb.append("</composite>");
		return sb.toString();
	}
}
class Component{
	public String name;
	public Service service;
	public String impl;
	public Ref ref;
	public List<Prop> props = new ArrayList<Prop>();
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("    <component name=\"" + name + "\">");
		sb.append("\r\n");
		sb.append(service);
		sb.append("\r\n");
		sb.append("        <implementation.java impl=\"" + impl + "\"/>");
		sb.append("\r\n");
		if (ref != null){
			sb.append(ref);
		    sb.append("\r\n");
		}
		for (Prop p : props){
			sb.append(p);
			sb.append("\r\n");
		}
		sb.append("    </component>");
		return sb.toString();
	}
}
class Service {
	public String name;
	public String interf;
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("        <service name=\"" + name + "\">");
		sb.append("\r\n");
		sb.append("            <interface.java interface=\"" + interf + "\"/>");
		sb.append("\r\n");
		sb.append("            <binding.sca/>");
		sb.append("\r\n");
		sb.append("        </service>");
		return sb.toString();
	}
}
class Ref {
	public String name;
	public String target;
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("        <reference name=\"" + name + "\" target=\"" + target + "\"/>");		
		return sb.toString();
	}
}
class Prop {
	public String name;
	public String value;
	
	public Prop(){}
	public Prop(String name){
		this.name = name;
	}
	
	@Override
	public int hashCode() {
		return name.hashCode();
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj ){
			return true;
		}
		if (obj instanceof Prop){
			Prop tmp = (Prop)obj;
			if (name.equals(tmp.name)){
				return true;
			}
		}
		return false;
	}
	
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("        <property name=\"" + name + "\" value=\"" + value + "\"/>");		
		return sb.toString();
	}
}
